﻿using Dapper;
using System.Data;
using System.Globalization;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using Volo.Abp.Users;
using YAPACS.BusinessObjects.Managements.Devices;
using YAPACS.Organizations;
using YAPACS.RisServer.Abstractions;
using YAPACS.RisServer.Services.ECharts;

namespace YAPACS.RisServer.Services
{
    public class ChartService(
                              IEChartFactoryService eChartFactoryService,
                              IRepository<Station ,Guid> stationRep,
                              IRepository<Department,Guid> departmentRep,
                              ICurrentUser currentUser,
                              ICurrentUserOrganization userOrganization
                             ) : DomainService, IChartService, ITransientDependency
    {
        private readonly IEChartFactoryService _eChartFactoryService = eChartFactoryService;
        private readonly IRepository<Station, Guid> _stationRep = stationRep;
        private readonly IRepository<Department,Guid> _departmentRep = departmentRep;
        private readonly ICurrentUser _currentUser =currentUser;
        private readonly ICurrentUserOrganization _userOrganization = userOrganization;


        #region  数据源处理
        /// <summary>
        /// 数据源填充
        /// 根据计算得来的categories 和 统计结果items 生成数据源
        /// </summary>
        /// <param name="connection">IDbConnection 连接对象</param>
        /// <param name="parameters">sql参数</param>
        /// <param name="categories">类目集合</param>
        /// <param name="sqlStr">sql语句</param>
        /// <param name="granularity">统计粒度</param>
        /// <param name="source">数据源的sorcery属性对象</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public List<object> FillDataSource(IDbConnection connection, DynamicParameters parameters, List<Category> categories, string sqlStr, string seriesName, List<object> source)
        {
            if (!string.IsNullOrEmpty(sqlStr))
            {
                var items = connection.Query(sqlStr, parameters);
                List<string> categoryArr = ["ItemName"];
                List<object> seriesWorkLoad = [seriesName];
                foreach (var category in categories)
                {
                    if (source.Count == 0)
                    {
                            categoryArr.Add(category.Name);
                    }
                    int count = 0;
                    foreach (var item in items)
                    {
                        if (category.Name.ToString().Contains(item.Name.ToString()))
                        {
                            count = (int)item.Count;
                            break;
                        }
                    }
                    seriesWorkLoad.Add(count);
                }
                if (source.Count == 0)
                {
                    source.Add(categoryArr);
                }
                source.Add(seriesWorkLoad);
                return source;
            }
            else
            {
                throw new Exception("sql语句不能为空!");
            }
        }
        #endregion


        #region 获取类目集合
        /// <summary>
        /// 获取类目集合
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <param name="granularity"></param>
        /// <returns></returns>
        public List<Category> GetCategories(DateTime startTime, DateTime endTime, string granularity)
        {
            List<Category> result;
            if (granularity == "Month")
            {
                result = GetMonthsBetween(startTime, endTime);
            }
            else if (granularity == "Week")
            {
                result = GetWeeksBetween(startTime, endTime);
            }
            else // Day
            {
                result = GetDaysBetween(startTime, endTime);
            }
            return result;
        }


        /// <summary>
        ///  计算日期时间段中包含的月份
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <returns>月份组成的类目列表</returns>
        public List<Category> GetMonthsBetween(DateTime startTime, DateTime endTime)
        {
            List<Category> categories = eChartFactoryService.GetNewCategoryList();
            DateTime currentTime = startTime;
            DateTime lastTimeOfEndMonth = endTime.AddMonths(1).AddDays(-endTime.Day).Date.AddHours(23).AddMinutes(59).AddSeconds(59);
            while (currentTime < lastTimeOfEndMonth)
            {
                Category category = eChartFactoryService.GetNewCategory();
                category.Name = currentTime.ToString("yyyy-MM");
                category.BeginTime = new DateTime(currentTime.Year, currentTime.Month, 1, 0, 0, 0);
                DateTime lastOfMonth = currentTime.AddMonths(1).AddDays(-currentTime.Day);
                category.EndTime = lastOfMonth.Date.AddHours(23).AddMinutes(59).AddSeconds(59);
                currentTime = currentTime.AddMonths(1);
                categories.Add(category);
            }

            categories = categories.GroupBy(c => c.Name).Select(g => g.First()).ToList();
            return categories;
        }
        #endregion



        #region 计算时间段中包含的周
        /// <summary>
        /// 计算时间段中包含的周
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="dateTime"></param>
        /// <returns>周组成的类目列表</returns>
        public List<Category> GetWeeksBetween(DateTime startTime, DateTime endTime)
        {
            List<Category> categories = [];
            DateTime currentTime = startTime;
            DateTime lastTimeOfEndWeek = GetStartDateOfWeek(endTime).Date.AddDays(6).AddHours(23).AddMinutes(59).AddSeconds(59);
            while (currentTime <= lastTimeOfEndWeek)
            {
                Category category = eChartFactoryService.GetNewCategory();
                category.Name = currentTime.Year.ToString() + "-" + ISOWeek.GetWeekOfYear(currentTime).ToString();
                category.BeginTime = GetStartDateOfWeek(currentTime);
                category.EndTime = category.BeginTime.AddDays(6).Date.AddHours(23).AddMinutes(59).AddSeconds(59);
                categories.Add(category);
                currentTime = currentTime.AddDays(7);
            }

            return categories.GroupBy(e => e.Name).Select(g => g.First()).ToList();
        }
        #endregion



        /// <summary>
        /// 获取日期所在周的开始时间
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public DateTime GetStartDateOfWeek(DateTime dateTime)
        {
            int diff = (int)dateTime.DayOfWeek - (int)DayOfWeek.Monday;
            if (diff < 0)
            {
                diff += 7;
            }
            return dateTime.AddDays(-diff).Date;
        }


        #region 计算时间段内日期的集合
        /// <summary>
        /// 计算时间段里包含的天
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <returns>天组成的类目列表</returns>
        public List<Category> GetDaysBetween(DateTime startTime, DateTime endTime)
        {
            List<Category> categories = [];
            DateTime currentTime = startTime;

            while (currentTime <= endTime)
            {
                Category category = _eChartFactoryService.GetNewCategory();
                category.Name = currentTime.Date.ToString("MM-dd");
                category.BeginTime = currentTime.Date;
                category.EndTime = currentTime.Date.AddHours(23).AddMinutes(59).AddSeconds(59);
                categories.Add(category);
                currentTime = currentTime.AddDays(1);
            }
            return categories;
        }


        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="stationCode">站点code</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<Object> GetUserInfo(string stationCode)
        {
            Station station = null;
            string stationName = null;
            if (!string.IsNullOrEmpty(stationCode))
            {
                station = await _stationRep.GetAsync(e => e.Code == stationCode);
                stationName = station.Name;
            }
            Department department = await _departmentRep.GetAsync(e => e.Oid == _userOrganization.DepartmentId);
            var result = new
            {
                stationName = stationName,
                userName = $"{_currentUser.Name}({_currentUser.UserName})",
                departmentName = department.Name
            };
            return result;
        }
        #endregion
    }
}
